package cz.muni.fi.pv112.cranesimulator.gui.components;

import cz.muni.fi.pv112.cranesimulator.gui.components.handlers.ControlKeysHandler;
import cz.muni.fi.pv112.cranesimulator.settings.Controls;
import cz.muni.fi.pv112.cranesimulator.utils.KeyCodeKeyTextTransformer;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Locale;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**
 *
 * @author Michal Ďuriš
 */
public class ControlKeyTextField extends JTextField {

    private static final int DEFAULT_COLUMN_COUNT = 5;

    private final Controls.Key controlKey;

    public ControlKeyTextField(Controls.Key controlKey) {

        this.controlKey = controlKey;

        init();
    }

    private void init() {
        setDocument(new ControlKeyDocument());
        setColumns(DEFAULT_COLUMN_COUNT);

        setKeyBindings();

        ControlKeysHandler.getInstance().addControlKeyItem(this);
    }

    private void setKeyBindings() {

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
                "left_arrow");
        getActionMap().put("left_arrow",
                new ControlKeyBindingAction(KeyEvent.VK_LEFT));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
                "right_arrow");
        getActionMap().put("right_arrow",
                new ControlKeyBindingAction(KeyEvent.VK_RIGHT));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up_arrow");
        getActionMap().put("up_arrow",
                new ControlKeyBindingAction(KeyEvent.VK_UP));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
                "down_arrow");
        getActionMap().put("down_arrow",
                new ControlKeyBindingAction(KeyEvent.VK_DOWN));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
        getActionMap().put("Enter",
                new ControlKeyBindingAction(KeyEvent.VK_ENTER));

        getInputMap()
                .put(KeyStroke.getKeyStroke(new Character(' '), 0), "Space");
        getActionMap().put("Space",
                new ControlKeyBindingAction(KeyEvent.VK_SPACE));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,
                InputEvent.CTRL_DOWN_MASK),
                "Control");
        getActionMap().put("Control",
                new ControlKeyBindingAction(KeyEvent.VK_CONTROL));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT,
                InputEvent.ALT_DOWN_MASK),
                "Alt");
        getActionMap().put("Alt",
                new ControlKeyBindingAction(KeyEvent.VK_ALT));

        getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT_GRAPH,
                InputEvent.ALT_GRAPH_DOWN_MASK),
                "Alt_graf");
        getActionMap().put("Alt_graf",
                new ControlKeyBindingAction(KeyEvent.VK_ALT_GRAPH));
    }

    public void loadControlKey() {
        setText(KeyCodeKeyTextTransformer.getKeyTextRepresentation(
                Controls.getInstance().getControlsKeyMapping(controlKey)));
    }

    public void storeControlKey() {

        Controls.getInstance().setControlsKeyMapping(controlKey,
                KeyCodeKeyTextTransformer
                .getKeyCode(getText()));
    }

    private class ControlKeyDocument extends PlainDocument {

        private static final long serialVersionUID = 1L;

        public ControlKeyDocument() {
        }

        @Override
        public void remove(int offs, int len) throws BadLocationException {
            super.remove(0, getLength());
        }

        @Override
        public void insertString(int offs, String str, AttributeSet a) throws
                BadLocationException {

            if (str == null || getText(0, getLength()).equalsIgnoreCase(str)) {
                return;
            }

            if (ControlKeysHandler.getInstance().isKeyAlreadyUsed(str)) {

                JOptionPane.showMessageDialog(null,
                        "This key is already used!",
                        "Error",
                        JOptionPane.ERROR_MESSAGE);
                return;
            }

            if (getLength() > 0) {
                this.remove(0, getLength());
            }

            if (str.length() > DEFAULT_COLUMN_COUNT) {
                setColumns(2 * DEFAULT_COLUMN_COUNT);
            }

            super.insertString(0, str.toLowerCase(Locale.ROOT), a);
        }

    }

    private static class ControlKeyBindingAction extends AbstractAction {

        private final int keyCode;

        public ControlKeyBindingAction(int keyCode) {
            this.keyCode = keyCode;
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            Object source = e.getSource();

            if (source instanceof JTextField) {
                ((JTextField) source).setText(KeyEvent.getKeyText(keyCode));
            }
        }

    }

}
